package com.core.gwt.place.client;

import com.google.gwt.user.client.Command;

/**
 * This class allows you to schedule the execution of some behavior only after
 * multiple asynchronous operations have completed, using a lock-count
 * mechanism.<br>
 * <br>
 * You add a lock before invoking each asynchronous operation and release a lock
 * after the asynchronous operation has completed. When the lock count reaches
 * zero - that is, the last lock is released - the blocked command gets
 * executed.<br>
 * <br>
 * Example:
 * 
 * <pre>
 * public class MyActivity {
 * ...
 *   {@literal @Override}
 *   public void start(AcceptsOneWidget panel, EventBus eventBus) {
 *     ...
 *     BlockedCommand blocked = new BlockedCommand() {
 *       {@literal @Override}
 *       public void execute() {
 *         ...
 *         // Show the widget only after the 
 *         // asynchronous initialization has completed
 *         panel.setWidget(view);         
 *       }
 *     };
 *     
 *     blocked.addLock();
 *     someService.getSomething(new AsyncCallback&lt;SomeResultType&gt;() {
 *       {@literal @Override}
 *       void onSuccess(SomeResultType result) {
 *         ...
 *         blocked.releaseLock();
 *       }
 *     });
 *     
 *     blocked.addLock();
 *     someOtherService.getSomethingElse(new AsyncCallback&lt;SomeOtherResultType&gt;() {
 *       {@literal @Override}
 *       void onSuccess(SomeOtherResultType result) {
 *         ...
 *         blocked.releaseLock();
 *       }
 *     });
 *   }
 * }
 * </pre>
 * 

 * 
 */
public abstract class BlockedCommand implements Command {
	private int lockCount = 0;
	private boolean executed = false;

	/**
	 * Increments the lock counter.
	 */
	public void addLock() {
		lockCount++;
	}

	/**
	 * Decrements the lock counter. When the lock count reaches zero, the
	 * {@link Command#execute()} method is invoked.
	 */
	public void releaseLock() {
		assert (lockCount > 0);
		lockCount--;
		if (lockCount == 0 && !executed) {
			execute();
			executed = true;
		}
	}
}
